package org.game.manager;

import com.google.common.collect.Maps;
import com.sojoys.artifact.manager.MessageManager;
import com.sojoys.artifact.tools.ToolList;
import com.sojoys.artifact.tools.ToolMap;
import org.cfg.*;
import org.cfg.cache.DiscreteDataCfgCache;
import org.cfg.cache.GrowUpCfgCache;
import org.cfg.cache.HeroProgressCfgCache;
import org.cfg.cache.LevelUpCfgCache;
import org.constant.*;
import org.constant.smallkey.PlayerDataSmallKey;
import org.game.constant.AttrConstant;
import org.game.db.bean.Formation;
import org.game.db.bean.Hero;
import org.game.db.bean.Player;
import org.game.db.bean.PlayerData;
import org.game.db.cache.FormationCache;
import org.game.db.cache.HeroCache;
import org.game.db.proxy.bean.HeroProxy;
import org.game.db.proxy.bean.PlayerProxy;
import org.game.db.vo.EquipmentVO;
import org.game.db.vo.PlayerDataVO.DiscreteVO;
import org.game.db.vo.SkinVO;
import org.game.log.LogHero;
import org.game.log.builder.LogDsp;
import org.game.log.dsp.GoodsDsp;
import org.game.log.dsp.HeroDsp;
import org.game.module.herobo.HeroBO;
import org.game.module.itembo.ItemBO;
import org.game.msgBuilder.HeroMsgBuilder;
import org.game.plugin.event.GameEvent;
import org.game.plugin.event.GameEventPlugin;
import org.game.protobuf.s2c.S2CHeroMsg.HeroExpInfo;
import org.game.protobuf.s2c.S2CHeroMsg.HeroInfo;
import org.game.protobuf.s2c.S2CItemMsg;
import org.game.protobuf.s2c.S2CShareMsg.ChangeType;
import org.game.util.ProtoUnit;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * @author : DengYing
 * @CreateDate : 2017年8月23日 上午11:29:38
 * @Description ：英雄管理器
 */
@SuppressWarnings("unchecked")
public class HeroManager {
	
	private HeroManager(){}
	
	private static HeroManager ME = new HeroManager();
	
	public static HeroManager me() {
		return ME;
	}
	
	/**
	 * 添加英雄
	 */
	public void addHero(Player player, HeroCfg cfg, LogDsp dsp){
		
		PlayerData playerData = player.getPlayerDatasFkPlayerId();
		DiscreteVO discreteVO = playerData.getPlayerDataProxy().getDiscreteVO();
		// 查看是否初始化助战英雄
		int helpFightHeroCid = discreteVO.getHelpFigntHeroCid();
		
		boolean createPlayer = PlayerManager.me().isCreatePlayer();
		Hero hero = new Hero(0L, cfg.getId(), 0, 1, 0, 1, 0 ,player.getId(),new HashMap<>());
		hero.insert();

		S2CItemMsg.ItemList.Builder itemChange = S2CItemMsg.ItemList.newBuilder();
		LogDsp log = LogDsp.newBuilder(GoodsDsp.GAIN_HERO).targetTag(hero.getCid());
		ItemManager.addSingleGoods(player, hero, null,itemChange,log, cfg.getDefaultSkin());

		// 计算战斗力
		calAttr(hero);
		
		LogDsp logDsp = LogDsp.newBuilder(HeroDsp.OBTAIN);
		LogHero.me().log(player.getId(), hero.getCid(), hero.getLvl(), hero.getLvl(), logDsp);
		
		PlayerProxy playerExt = player.getPlayerProxy();

		if (!createPlayer) {
			HeroInfo heroInfo = HeroMsgBuilder.createHeroInfo(ChangeType.ADD, hero,dsp.getDsp());
			playerExt.sendMsg(MessageManager.me().create(ItemBO.getItems, ProtoUnit.toByte(itemChange.build())));
			playerExt.sendMsg(MessageManager.me().create(HeroBO.sendHero, ProtoUnit.toByte(heroInfo)));

		}else {
			if (helpFightHeroCid == 0) {
				// 默认设置助战状态
				playerExt.setHelpHero(hero);
			}
			// 初始英雄上阵
			Formation formation = FormationCache.me().getByPlayerIdType(player.getId(), FormationConstant.TYPE_MAIN);
			formation.getStance().add(hero.getId());
			formation.update();			
		}
		playerExt.getHerosByDbId().put(hero.getId(), hero);
		playerExt.getHerosByCid().put(hero.getCid(),hero);

		// 激活精灵
		RoleManager.me().activateRole(player, cfg.getRole());
	}

	/**
	 * 更换皮肤
	 * @param hero 英雄
	 * @param skinVO 新皮肤
	 * @param beforeSkinVO 老皮肤
	 */
	public void changeHeroSkin(Hero hero,SkinVO skinVO,SkinVO beforeSkinVO){
		if (beforeSkinVO != null){
			beforeSkinVO.setHeroId(0);
			beforeSkinVO.update();
		}

		skinVO.setHeroId(hero.getId());
		skinVO.update();

		hero.getHeroProxy().setSkinVo(skinVO);
	}

	public void calAttr(Hero hero) {

		// 配置ID * 100 + 突破等级
		int attrId = hero.getHeroProxy().getConfig().getAttribute() * 100 + hero.getAdvancedLvl();
		GrowUpCfg growUp = GrowUpCfgCache.me().getById(attrId);
		
		
		int progressId =  hero.getHeroProxy().getConfig().getAttribute() * 100 + hero.getHeroProxy().getQuality();
		HeroProgressCfg heroProgress = HeroProgressCfgCache.me().getById(progressId);
		
		Map<Integer, Integer> attr = Maps.newHashMapWithExpectedSize(AttrConstant.ATTR_COUNT);
		// 突破属性
		attr.putAll(growUp.getBaseAttr());
		// 突破成长
		changeAttr(attr, calUpAttr(growUp.getUpAttr(), hero.getLvl()));
		
		// 进阶属性
		changeAttr(attr, heroProgress.getBaseAttr());
		// 进阶成长
		changeAttr(attr, calUpAttr(heroProgress.getUpAttr(), hero.getLvl()));
		
		// 装备
		changeAttr(attr, EquipmentManager.me().calcEquipAttr(hero));
		// 天使
		changeAttr(attr, calAngelAttr(hero));
		
		// 计算加成属性值
//		calAttrRatio(attr);
		hero.getHeroProxy().setAttr(attr);
		
		// 计算战斗力
		changeFightPower(hero);
	}

	private void changeFightPower(Hero hero) {
		DiscreteDataCfg cfg = DiscreteDataCfgCache.me().getById(DiscreteDataID.FIGHT_POWER_RULE);
		// 英雄品质战力
 		List<Integer> rarityzl = ToolMap.getList("rarityzl", cfg.getData());
 		
 		// 英雄等级战力
 		List<Integer> herolvlzl = ToolMap.getList("herolvlzl", cfg.getData());
 		
 		// 英雄突破战力
 	 	List<Integer> growupzl = ToolMap.getList("growupzl", cfg.getData());
 	 	
 	 	List<Integer> equipzl = ToolMap.getList("equipzl", cfg.getData());
 	 	
 	 	List<Integer> equiplvlzl = ToolMap.getList("equiplvlzl", cfg.getData());
 	 	// 天使等级战力
 	 	List<Integer> angelzl = ToolMap.getList("angelzl", cfg.getData());
 	 	// 天使技能点对应的战斗力
 	 	HeroProxy heroProxy = hero.getHeroProxy();
 	 	int angelpoint = ToolMap.getInt("angelpoint", cfg.getData(),1) * heroProxy.getAlreadyUseSkillPiont();
		
		int heroFightPower = 0;
		
		heroFightPower+= rarityzl.get(heroProxy.getQuality() - 1);
		heroFightPower+= hero.getLvl() * herolvlzl.get(heroProxy.getQuality() - 1);
		heroFightPower+= growupzl.get(hero.getAdvancedLvl());
		heroFightPower+= angelzl.get(hero.getAngelLvl()-1) + angelpoint;
		
		Map<Integer, EquipmentVO> equipment = heroProxy.getEquipment();
		for (Entry<Integer, EquipmentVO> e : equipment.entrySet()) {
			int star = e.getValue().getCfg().getStar();
			heroFightPower+=(equipzl.get(star - 1) + (equiplvlzl.get(star - 1)) * e.getValue().getLevel());
		}
		heroProxy.changeFightPower(heroFightPower);
	}

	/** 累加属性 */
	private void changeAttr(Map<Integer, Integer> attr, Map<Integer, Integer> in) {
		for (Entry<Integer, Integer> entry : in.entrySet()) {
			int newVal = ToolMap.getInt(entry.getKey(), attr, 0) + entry.getValue();
			attr.put(entry.getKey(), newVal);
		}
	}

	/**
	 * 计算成长属性 <br/>
	 * 公式 = 成长属性 * 英雄等级
	 * @param in
	 * @param heroLvl
	 * @return
	 */
	private Map<Integer, Integer> calUpAttr(Map<Integer, Integer> in, int heroLvl) {
		Map<Integer, Integer> arrr = Maps.newHashMapWithExpectedSize(AttrConstant.ATTR_COUNT);
		for (Entry<Integer, Integer> entry : in.entrySet()) {
			arrr.put(entry.getKey(), entry.getValue() * heroLvl);
		}
		return arrr;
	}
	
	/**
	 * 计算天使属性 <br/>
	 * 公式 = 成长属性 * 英雄等级
	 * @param in
	 * @param heroLvl
	 * @return
	 */
	private Map<Integer, Integer> calAngelAttr(Hero hero) {
		Map<Integer, Integer> attr = ToolList.getMap(hero.getAngelLvl()-1, hero.getHeroProxy().getConfig().getSkillPoint());
		return attr;
	}
	
	
	/**
	 * 计算属性加成 <br/>
	 * 公式 = 成长属性 * 英雄等级
	 * @param in
	 * @param heroLvl
	 * @return
	 */
	private Map<Integer, Integer> calAttrRatio(Map<Integer, Integer> in) {
		Map<Integer, Integer> arrr = Maps.newHashMapWithExpectedSize(AttrConstant.ATTR_COUNT);
		for (Entry<Integer, Integer> entry : in.entrySet()) {
			int attrType = entry.getKey();
			if (attrType < AttrConstant.BASE_VAL) {
				// 取得加成比例
				double ratio =  ToolMap.getInt(attrType + AttrConstant.BASE_VAL, in , 0) / AttrConstant.BASE_RATIO;
				int newVal = (int) (entry.getValue() * (1 + ratio));
				in.put(attrType, newVal);
			}
		}
		return arrr;
	}
	
	/**
	 * 增加上阵英雄经验
	 * @param hero
	 * @param exp
	 */
	public void addTeamExp(Player player,long addExp) {
		Formation formation = FormationCache.me().getByPlayerIdType(player.getId(), FormationConstant.TYPE_MAIN);
		
		List<Long> heroIds = formation.getStance();
		for (Long heroId : heroIds) {
			if (heroId==null || 0 == heroId) {
				continue;
			}
			
			Hero hero = HeroCache.me().getById(heroId);
			addExp(addExp, hero);
		}
	}

	/**
	 * 添加英雄经验
	 * @param addExp
	 * @param hero
	 */
	public void addExp(long addExp, Hero hero) {
		
		DiscreteDataCfg discreteData = DiscreteDataCfgCache.me().getById(DiscreteDataID.MAX_LVL_CONFIG);
		int maxLvl = ToolMap.getInt("hmaxlvl", discreteData.getData(),0);
		long addHeroExp = addExp;
		int nowLv = hero.getLvl();
		int oldLv = hero.getLvl();
		LevelUpCfg nextLvl = LevelUpCfgCache.me().getById(nowLv + 1);
		Player player = hero.getPlayerPkPlayerId();
		int limitLvl = hero.getHeroProxy().getMaxLvl();
		
		limitLvl = Math.min(maxLvl, limitLvl);
		
		// 已达最大等级
		if (nextLvl == null || nowLv > limitLvl) {
			return;
		}
		
		LevelUpCfg nowLvl = null;
		while (addHeroExp > 0) {
			long total = hero.getExp() + addHeroExp;
			nowLvl = LevelUpCfgCache.me().getById(nowLv);
			if (nowLvl==null || nowLv > limitLvl) {
				break;
			}
			nextLvl = LevelUpCfgCache.me().getById(nowLv + 1);
			
			long maxExp = nowLvl.getHeroExp();
			addHeroExp = total - maxExp;
			if (addHeroExp >= 0) {
				if (nowLv >= limitLvl) {
					hero.setExp(Math.min(total, maxExp));	
					break;
				}else if(nextLvl != null && nextLvl.getId() <= limitLvl){
					nowLv+=1;
					hero.setExp(0);					
				}else {
					hero.setExp(Math.min(total, maxExp));
					break;
				}
			}else {
				hero.setExp(Math.min(total, maxExp));
				break;
			}
		}
		
		hero.setLvl(nowLv);
		hero.update();
		
		PlayerProxy playerExt = player.getPlayerProxy();
		if (nowLv!=oldLv) {
			// 更新英雄整体信息
			HeroManager.me().calAttr(hero);
			playerExt.sendMsg(MessageManager.me().create(HeroBO.sendHero, ProtoUnit.toByte(HeroMsgBuilder.createHeroInfo(ChangeType.UPDATE, hero))));

			// 触发英雄事件
			Map<String, Object> in = Maps.newHashMap();
			in.put(EventConditionKey.CONDITION_TYPE, EventConditionType.HERO_MAX_LVL);
			in.put(EventConditionKey.HERO_CID, hero.getCid());
			in.put(EventConditionKey.OLD_LEVEL, oldLv);
			in.put(EventConditionKey.NOW_LEVEL, nowLv);
			GameEvent event = new GameEvent(player, EventType.HERO_CHANGE, in);
			GameEventPlugin.syncSubmit(event);
			
			LogDsp logDsp = LogDsp.newBuilder(HeroDsp.UP_LVL);
			LogHero.me().log(player.getId(), hero.getCid(), oldLv, nowLv, logDsp);
		}else {
			// 更新英雄经验信息
			HeroExpInfo.Builder builder = HeroExpInfo.newBuilder();
			builder.setCid(hero.getCid());
			builder.setId(Long.toString(hero.getId()));
			builder.setExp(hero.getExp());
			playerExt.sendMsg(MessageManager.me().create(HeroBO.pushHeroExp, ProtoUnit.toByte(builder.build())));
		}
	}


	public static void sendHeroInfo2Client(Player player,Hero hero,ChangeType ct){
		HeroManager.me().calAttr(hero);
		player.getPlayerProxy().sendMsg(MessageManager.me().create(HeroBO.sendHero, ProtoUnit.toByte(HeroMsgBuilder.createHeroInfo(ct, hero))));

	}
}
